package com.smart.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.smart.common.PageInfo;
import com.smart.common.enums.BooleanEnum;
import com.smart.common.utils.AssertUtil;
import com.smart.context.SessionContext;
import com.smart.mapper.ProjectMapper;
import com.smart.model.domain.ProjectDO;
import com.smart.model.dtomapper.QrCodeDtoMapper;
import com.smart.model.domain.QrCodeDO;
import com.smart.mapper.QrCodeMapper;
import com.smart.model.request.QrCodeRequest;
import com.smart.service.QrCodeService;
import com.smart.model.convert.QrCodeConvert;
import com.smart.model.vo.QrCodeVO;
import com.smart.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhanghong
 */
@Service
public class QrCodeServiceImpl extends ServiceImpl<QrCodeMapper, QrCodeDO> implements QrCodeService {
    @Autowired
    private QrCodeMapper qrCodeMapper;
    @Value("${qrcode.url}")
    private String qrcodeUrl;
    @Autowired
    private ProjectMapper projectMapper;


    /**
     * 出入场二维码生成
     * @param request
     * @param response
     * @param transfer 是否数据迁移
     * @param projectId 数据迁移时projectId必传
     * @param address  进离场地址
     * @param addressType  true:进场  false:离场
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long qrCode(HttpServletRequest request, HttpServletResponse response, Boolean transfer, Long projectId, String address, Boolean addressType) {
        if (projectId == null) {
            projectId = SessionContext.getProjectId();
        }
        QrCodeDO qrCode = new QrCodeDO();
        qrCode.setProjectId(projectId);
        if (addressType) {
            qrCode.setType(BooleanEnum.TRUE.getCode());
        }else {
            qrCode.setType(BooleanEnum.FALSE.getCode());
        }
        List<QrCodeDO> qrCodeDOS = qrCodeMapper.selectDOList(qrCode);
        if (!transfer) {
            AssertUtil.assertTrue(qrCodeDOS.size()<=10,"进离场二维码个数已达到上限");
        }
        //将二维码地址入库
        QrCodeDO qrCodeDO = new QrCodeDO();
        qrCodeDO.setProjectId(projectId);
        qrCodeDO.setAddress(address);
        if (addressType) {
            qrCodeDO.setType(BooleanEnum.TRUE.getCode());
        }else {
            qrCodeDO.setType(BooleanEnum.FALSE.getCode());
        }
        qrCodeDO.setCreateTime(DateUtils.getNowDate());
        qrCodeMapper.insertDO(qrCodeDO);
        String url = qrcodeUrl+"/lsfangke/#/" ;
        if (!addressType) { //离场地址
            url = qrcodeUrl+"/lsfangke/#/outWorkSubmit" ;
        }
        int width = 200; // 二维码宽度
        int height = 200; // 二维码高度
        try{
            // 设置二维码的一些参数
            ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
            int margin = 1;

            // 设置二维码的编码格式
            String charset = "UTF-8";

            // 创建带地名信息的URL
            String fullUrl = url + "?projectId=" + projectId+"&id="+qrCodeDO.getId()+"&doorName="+address;

            // 创建二维码写入器
            QRCodeWriter qrCodeWriter = new QRCodeWriter();

            // 创建二维码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel);
            hints.put(EncodeHintType.MARGIN, margin);
            hints.put(EncodeHintType.CHARACTER_SET, charset);

            // 创建二维码矩阵
            BitMatrix bitMatrix = qrCodeWriter.encode(fullUrl, BarcodeFormat.QR_CODE, width, height, hints);

            // 创建二维码缓冲图像
            BufferedImage qrCodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

            // 将二维码矩阵绘制到缓冲图像中
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    qrCodeImage.setRGB(x, y, bitMatrix.get(x, y) ? 0x000000 : 0xFFFFFF);
                }
            }

            // 将二维码保存为临时文件
            String fileName = address + "-离场";
            if (addressType) {
                fileName = address + "-进场";
            }
            File tempFile = File.createTempFile(fileName, ".png");
            ImageIO.write(qrCodeImage, "png", tempFile);

            //上传二维码图像
            // 创建MultiValueMap
            MultiValueMap<String, Object> bodyMap = new LinkedMultiValueMap<>();
            bodyMap.add("file", new FileSystemResource(tempFile));

            // 创建HttpHeaders
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

            // 创建HttpEntity
            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(bodyMap, headers);

            // 创建RestTemplate
            RestTemplate restTemplate = new RestTemplate();

            // 发送POST请求
            ResponseEntity<String> result = restTemplate.postForEntity(qrcodeUrl+"/smart/file/upload", requestEntity, String.class);

            //将二维码地址入库
            String body = result.getBody();
            String qrAdress = JSONObject.parseObject(body).getString("data");
            qrCodeDO.setQrCodeUrl(qrAdress);
            qrCodeMapper.updateDO(qrCodeDO);
            tempFile.delete();
            return qrCodeDO.getId();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public QrCodeVO getByKey(long id) {
        QrCodeDO qrCodeDO = qrCodeMapper.selectDOById(id);
        QrCodeVO qrCodeVO = QrCodeDtoMapper.INSTANCE.do2VO(qrCodeDO);
        if (qrCodeDO!=null) {
            ProjectDO projectDO = projectMapper.selectDOById(qrCodeDO.getProjectId());
            if (!ObjectUtils.isEmpty(projectDO)){
                qrCodeVO.setProjectName(projectDO.getProjectName());
            }
        }
        return qrCodeVO;
    }

    @Override
    public PageInfo<QrCodeVO> pageQuery(QrCodeRequest request) {
        long count = qrCodeMapper.pageCount(request);
        List<QrCodeDO> list = qrCodeMapper.pageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<QrCodeVO> qrCodeVOList = QrCodeConvert.buildQrCodeVoList(list);
        return new PageInfo(request.getPageNum(), request.getPageSize(), qrCodeVOList, count);
    }

    @Override
    public List<QrCodeVO> listQuery(QrCodeRequest request) {
        QrCodeDO qrCodeDO = QrCodeDtoMapper.INSTANCE.request2DO(request);
        if (ObjectUtils.isEmpty(request.getProjectId())){
            qrCodeDO.setProjectId(SessionContext.getProjectId());
        }
        List<QrCodeDO> list = qrCodeMapper.selectDOList(qrCodeDO);
        List<QrCodeVO> qrCodeVOS = QrCodeConvert.buildQrCodeVoList(list);
        return qrCodeVOS;
    }

    @Override
    public Boolean add(QrCodeRequest request) {
        QrCodeDO qrCodeDO = QrCodeDtoMapper.INSTANCE.request2DO(request);
        save(qrCodeDO);
        return true;
    }

    @Override
    public Boolean updateByKey(QrCodeRequest request) {
        QrCodeDO qrCodeDO = QrCodeDtoMapper.INSTANCE.request2DO(request);
        qrCodeMapper.updateDO(qrCodeDO);
        return true;
    }

    @Override
    public Boolean deleteByKey(long id) {
        qrCodeMapper.deleteDOById(id);
        return true;
    }


}
